/*
 * MegaMek - Copyright (C) 2007-2008 Ben Mazur (bmazur@sev.org)
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the Free
 *  Software Foundation; either version 2 of the License, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 */
package megamek.server.victory;

import java.util.ArrayList;
import java.util.HashMap;

import megamek.common.IGame;
import megamek.common.Report;

/**
 * interface for classes judging whether a victory occurred or not. these
 * classes may not modify game state. Reporting must be done via the given
 * interface. classes also should not have any nasty internal state outside
 * methods this will guarantee them to act _only_ based on gamestate The only
 * case where this should be done is in cases where you have to count occurances
 * of some action or duration of something. In this case the information should
 * be stored in the context-object NOTE: if you delegate from one victory-class
 * instance to other, they must be created in similar fashion (ie. constructed
 * at the same time and destroyed at the same time) to guarantee proper working
 * also , if you delegate, you should delegate each time to guarantee that
 * victorypoint-counting and duration-counting implementations get access to
 * game state every round. NOTE2: calling victory 1 time or n times per round
 * should not make a difference! victories counting rounds must not assume that
 * they are called only once per round NOTE3: dont even think about making
 * different victoryclasses communicate straight or via context-object ;) NOTE4:
 * victories should take into account in their reporting (adding reports to the
 * result-object) that their results might be filtered. So the reports should be
 * mostly of the "what is the score" -type (player A occupies the victory
 * location) or fact-type (Player A has destroyed player B's commander)
 */
public interface Victory {
    /**
     * @param game - the game (state) we are playing
     * @param context - a map Strings to simple serializable objects (preferably
     *            Integers , Strings ,Doubles etc) which are used to store state
     *            between executions if such feature is absolutely required.. as
     *            a key you should use something atleast class- specific to
     *            limit namespace collisions
     * @return a result with true if victory occured, false if not must not
     *         return null MUST NOT modify game state!
     */
    public Result victory(IGame game, HashMap<String, Object> context);

    /**
     * result class which can be queried for winner and if victory occurred
     * victory might be true and winner "None" if the players have drawn winner
     * might be NONE and team set to winning team. NOTE: a player which is in a
     * team, should not win by himself. so if there is a winning team and a
     * winning player it is a draw this should actually be a victorypoint-like
     * structure with boolean for "game end" (victory) and 0.0(loss) to
     * 1.0(victory) score for each team and player
     */
    public static interface Result {
        /**
         * @return true if the game is about to end since someone has completed
         *         the victory conditions
         */
        public boolean victory();

        /**
         * @return player victory level 0.0(total loss) to 1.0 (total victory)
         *         anybody not listed can be assumed to be at 0.0 score
         */
        public double getPlayerScore(int id);

        /**
         * list players
         */
        public int[] getPlayers();

        /**
         * list team scores all teams which are not listed, can be assumed to be
         * at 0.0
         */
        public double getTeamScore(int id);

        /**
         * list teams
         */
        public int[] getTeams();

        /**
         * @return true if this is a winning team id (draw == win in this case)
         */
        public boolean isWinningTeam(int id);

        /**
         * @return true if this is a winning player id (draw == win in this
         *         case)
         */
        public boolean isWinningPlayer(int id);

        /**
         * @return arrayList of reports generated by the victory checking.
         *         Usually empty when no victory should never be null might
         *         contain reports about victoryconditions which are about to be
         *         filled or are time triggered
         */
        public ArrayList<Report> getReports();

        /**
         * @return id of the winning team, Player.TEAM_NONE if it's a draw
         */
        public int getWinningTeam();

        /**
         * @return id of the winning player, Player.TEAM_NONE if it's a draw
         */
        public int getWinningPlayer();

        /**
         * @return if this is a draw
         */
        public boolean isDraw();
    }
}